/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.form;
import org.openide.TopManager;
import org.openide.NotifyDescriptor;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileLock;
import org.openide.util.NbBundle;
import org.netbeans.modules.form.forminfo.*;
import org.netbeans.modules.form.*;
import org.netbeans.modules.form.compat2.*;
import org.netbeans.modules.form.compat2.layouts.DesignLayout;
import java.beans.BeanInfo;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.util.*;
/**
*
* @author Ian Formanek
*/
public class TuborgPersistenceManager extends PersistenceManager {
/** Constant used for signing the classes loaded by default classloader */
final static byte LOADER_DEFAULT = 0x01;
// Constants to recognize form files saved from Tuborg
private static byte MAGIC_0 = -84;
private static byte MAGIC_1 = -19;
private static byte MAGIC_2 = 0;
private static byte MAGIC_3 = 5;
// FINALIZE DEBUG METHOD
public void finalize () throws Throwable {
super.finalize ();
if (System.getProperty ("netbeans.debug.form.finalize") != null) {
System.out.println("finalized: "+this.getClass ().getName ()+", instance: "+this); // NOI18N
}
} // FINALIZE DEBUG METHOD
/** A method which allows the persistence manager to provide infotrmation on whether
* is is capable to store info about advanced features provided from Developer 3.0
* - all persistence managers except the one providing backward compatibility with
* Developer 2.X should return true from this method.
* @return true if this PersistenceManager is capable to store advanced form features, false otherwise
*/
public boolean supportsAdvancedFeatures () {
return false;
}
/** A method which allows the persistence manager to check whether it can read
* given form format.
* @return true if this PersistenceManager can load form stored in the specified form, false otherwise
* @exception IOException if any problem occured when accessing the form
*/
public boolean canLoadForm (FormDataObject formObject) throws IOException {
InputStream is = null;
try {
is = formObject.getFormEntry ().getFile ().getInputStream();
byte[] bytes = new byte[4];
int len = is.read (bytes);
return ((len == 4) && (bytes[0] == MAGIC_0) && (bytes[1] == MAGIC_1) && (bytes[2] == MAGIC_2) && (bytes[3] == MAGIC_3));
} catch (Throwable t) {
if (t instanceof ThreadDeath) {
throw (ThreadDeath)t;
}
return false;
}
finally {
if (is != null)
is.close();
}
}
/** Called to actually load the form stored in specified formObject.
* @param formObject the FormDataObject which represents the form files
* @return the FormManager2 representing the loaded form or null if some problem occured
* @exception IOException if any problem occured when loading the form
*/
public FormManager2 loadForm (FormDataObject formObject) throws IOException {
FormManager2 formManager2 = null;
InputStream is = null;
try {
is = formObject.getFormEntry ().getFile ().getInputStream();
} catch (FileNotFoundException e) {
throw new IOException ("Form file not found"); // NOI18N
}
ObjectInputStream ois = null;
try {
ois = new org.openide.util.io.NbObjectInputStream(is);
// deserialization from stream
Object deserializedForm = null;
try {
deserializedForm = ois.readObject ();
} catch (ClassNotFoundException e) {
throw new IOException ("Form type not found: "+e.getMessage ()); // NOI18N
}
// create new objects from Backward compatibility classes
RADForm radForm = null;
if (deserializedForm == null) {
throw new IOException ("The form file does not contain a valid form"); // NOI18N
} else if (! (deserializedForm instanceof DesignForm)) {
throw new IOException ("Unknown form type: "+deserializedForm.getClass ().getName ()); // NOI18N
} else {
FormInfo info = null;
if (deserializedForm instanceof JFrameForm) {
info = new JFrameFormInfo ();
} else if (deserializedForm instanceof JDialogForm) {
info = new JDialogFormInfo ();
} else if (deserializedForm instanceof JPanelForm) {
info = new JPanelFormInfo ();
} else if (deserializedForm instanceof JAppletForm) {
info = new JAppletFormInfo ();
} else if (deserializedForm instanceof JInternalFrameForm) {
info = new JInternalFrameFormInfo ();
} else if (deserializedForm instanceof FrameForm) {
info = new FrameFormInfo ();
} else if (deserializedForm instanceof DialogForm) {
info = new DialogFormInfo ();
} else if (deserializedForm instanceof PanelForm) {
info = new PanelFormInfo ();
} else if (deserializedForm instanceof AppletForm) {
info = new AppletFormInfo ();
}
radForm = new RADForm (info);
formManager2 = new FormManager2 (formObject, radForm);
RADVisualContainer topComp = (RADVisualContainer)radForm.getTopLevelComponent ();
RADFormNode topNode = ((DesignForm)deserializedForm).formManager.rootNode;
// process non-visual components
Object[] nonVisualNodes = topNode.nonVisualsNode.nodeArray.array;
RADComponent[] nonVisualsComps = new RADComponent [nonVisualNodes.length];
for (int i = 0; i < nonVisualNodes.length; i++) {
RADNode node = (RADNode)nonVisualNodes[i];
if (node instanceof RADMenuNode) {
nonVisualsComps[i] = new RADMenuComponent ();
nonVisualsComps[i].initialize (formManager2);
nonVisualsComps[i].setComponent (node.beanClass);
nonVisualsComps[i].setName (node.componentName);
convertComponent (node, nonVisualsComps[i]);
RADComponent[] subs = createMenuHierarchy ((RADMenuNode)node, formManager2);
((RADMenuComponent)nonVisualsComps[i]).initSubComponents (subs);
} else {
nonVisualsComps[i] = new RADComponent ();
nonVisualsComps[i].initialize (formManager2);
nonVisualsComps[i].setComponent (node.beanClass);
nonVisualsComps[i].setName (node.componentName);
convertComponent (node, nonVisualsComps[i]);
}
}
formManager2.initNonVisualComponents (nonVisualsComps);
convertComponent (topNode, topComp);
RADComponent[] subComps = createHierarchy ((((DesignForm)deserializedForm).formManager.rootNode), formManager2);
topComp.initSubComponents (subComps);
topComp.setDesignLayout (((RADContainerNode)topNode).designLayout);
String menu = ((RADFormNode)topNode).menu;
if ((menu != null) && (topComp instanceof RADVisualFormContainer)) {
((RADVisualFormContainer)topComp).setFormMenu (menu);
}
}
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
if (System.getProperty ("netbeans.debug.form") != null) {
e.printStackTrace ();
}
}
}
}
return formManager2;
}
/** Called to actually save the form represented by specified FormManager2 into specified formObject.
* @param formObject the FormDataObject which represents the form files
* @param manager the FormManager2 representing the form to be saved
* @exception IOException if any problem occured when saving the form
*/
public void saveForm (FormDataObject formObject, FormManager2 manager) throws IOException {
FileLock lock = null;
try {
lock = formObject.getFormEntry ().getFile ().lock ();
OutputStream os = formObject.getFormEntry ().getFile ().getOutputStream(lock);
// we first save into memory to prevent corrupting the form file
// if something goes wrong
java.io.ByteArrayOutputStream barros = new java.io.ByteArrayOutputStream (10000);
ObjectOutputStream oos = new X2ObjectOutputStream(barros);
oos.writeObject (createOldForm (formObject, manager));
oos.close ();
// now it is safely written in memory, so we can save it to the file
barros.writeTo(os);
} catch (IOException e) {
TopManager.getDefault ().notify (new NotifyDescriptor.Message (
java.text.MessageFormat.format (
NbBundle.getBundle (FormEditorSupport.class).getString ("ERR_SavingForm"),
new Object[] { formObject.getName (), e.getClass ().getName ()}
),
NotifyDescriptor.ERROR_MESSAGE
)
);
e.printStackTrace ();
} finally {
if (lock != null) {
lock.releaseLock ();
}
}
}
// -----------------------------------------------------------------------------
// private methods -> Backward compatibility
private static RADComponent[] createHierarchy (RADContainerNode node, FormManager2 formManager2) {
RADNode nodes[] = node.getSubNodes ();
RADComponent[] comps = new RADComponent [nodes.length];
for (int i = 0; i < nodes.length; i++) {
if (nodes[i] instanceof RADContainerNode) {
comps[i] = new RADVisualContainer ();
} else if (nodes[i] instanceof RADVisualNode) {
comps[i] = new RADVisualComponent ();
} else {
comps[i] = new RADComponent ();
}
comps[i].initialize (formManager2);
comps[i].setComponent (nodes[i].beanClass);
comps[i].setName (nodes[i].componentName);
convertComponent (nodes[i], comps[i]);
if (nodes[i] instanceof RADContainerNode) {
RADComponent[] subs = createHierarchy ((RADContainerNode)nodes[i], formManager2);
((ComponentContainer)comps[i]).initSubComponents (subs);
((RADVisualContainer)comps[i]).setDesignLayout (((RADContainerNode)nodes[i]).designLayout);
}
}
return comps;
}
private static RADComponent[] createMenuHierarchy (RADMenuNode node, FormManager2 formManager2) {
Object nodes[] = node.getSubNodes ();
RADComponent[] comps = new RADComponent [nodes.length];
for (int i = 0; i < nodes.length; i++) {
Class beanClass;
if (nodes[i] instanceof RADMenuNode.MenuSeparatorNode) {
comps[i] = new RADMenuItemComponent ();
if ((node.type == RADMenuItemNode.T_MENU) || (node.type == RADMenuItemNode.T_POPUPMENU)) {
beanClass = org.netbeans.modules.form.Separator.class;
} else {
beanClass = javax.swing.JSeparator.class;
}
comps[i].initialize (formManager2);
comps[i].setComponent (beanClass);
if ((node.type == RADMenuItemNode.T_JMENU) || (node.type == RADMenuItemNode.T_JPOPUPMENU)) {
// only swing separators have instance variable
comps[i].setName (formManager2.getVariablesPool ().getNewName (beanClass));
}
} else if (nodes[i] instanceof RADNode) {
beanClass = ((RADNode)nodes[i]).beanClass;
if (nodes[i] instanceof RADMenuNode) {
comps[i] = new RADMenuComponent ();
} else if (nodes[i] instanceof RADMenuItemNode) {
comps[i] = new RADMenuItemComponent ();
} else {
comps[i] = new RADComponent ();
}
comps[i].initialize (formManager2);
comps[i].setComponent (beanClass);
comps[i].setName (((RADNode)nodes[i]).componentName);
convertComponent ((RADNode)nodes[i], comps[i]);
if (nodes[i] instanceof RADMenuNode) {
RADComponent[] subs = createMenuHierarchy ((RADMenuNode)nodes[i], formManager2);
((ComponentContainer)comps[i]).initSubComponents (subs);
}
}
}
return comps;
}
private static void convertComponent (RADNode node, RADComponent comp) {
Map origChanged = node.changedValues;
BeanInfo bi = comp.getBeanInfo ();
PropertyDescriptor[] pds = bi.getPropertyDescriptors ();
for (Iterator it = origChanged.keySet ().iterator (); it.hasNext (); ) {
Object key = it.next ();
for (int i = 0; i < pds.length; i++) {
if (key.equals (pds[i].getName ())) {
try {
comp.restorePropertyValue (pds[i], origChanged.get (key));
} catch (IllegalArgumentException e) {
// [PENDING]
} catch (IllegalAccessException e) {
// [PENDING]
} catch (java.lang.reflect.InvocationTargetException e) {
// [PENDING]
}
break;
}
}
}
Hashtable eventHandlers = node.eventHandlers;
comp.initDeserializedEvents (eventHandlers);
// process constraints on visual components
if (node instanceof RADVisualNode) {
HashMap map = ((RADVisualNode)node).constraints;
((RADVisualComponent)comp).initConstraints (map);
}
}
// -----------------------------------------------------------------------------
// private methods -> Forward compatibility
private static DesignForm createOldForm (FormDataObject formObject, FormManager2 formManager2) {
DesignForm designForm = null;
FormInfo info = formManager2.getRADForm ().getFormInfo ();
if (info instanceof JFrameFormInfo) {
designForm = new JFrameForm ();
} else if (info instanceof JDialogFormInfo) {
designForm = new JDialogForm ();
} else if (info instanceof JPanelFormInfo) {
designForm = new JPanelForm ();
} else if (info instanceof JAppletFormInfo) {
designForm = new JAppletForm ();
} else if (info instanceof JInternalFrameFormInfo) {
designForm = new JInternalFrameForm ();
} else if (info instanceof FrameFormInfo) {
designForm = new FrameForm ();
} else if (info instanceof DialogFormInfo) {
designForm = new DialogForm ();
} else if (info instanceof PanelFormInfo) {
designForm = new PanelForm ();
} else if (info instanceof AppletFormInfo) {
designForm = new AppletForm ();
}
FormManager formManager = new FormManager ();
RADFormNode rootNode = new RADFormNode ();
NonVisualsNode nonVisualsNode = new NonVisualsNode ();
RADNodeArray nodeArray = new RADNodeArray ();
// >> RADNodeArray
// 1. containerNode [RADContainer]
// 2. array [Object[]]
nodeArray.containerNode = nonVisualsNode;
RADComponent[] nonVisualComponents = formManager2.getNonVisualComponents ();
RADNode[] nonVisualNodes = new RADNode[nonVisualComponents.length];
for (int i = 0; i < nonVisualComponents.length; i++) {
if (nonVisualComponents[i] instanceof RADMenuComponent) {
nonVisualNodes[i] = new RADMenuNode ();
} else {
nonVisualNodes[i] = new RADNode ();
}
convertComponentBack (nonVisualComponents[i], nonVisualNodes [i]);
}
nodeArray.array = nonVisualNodes;
// >> NonVisualsNode
// 1. designForm [DesignForm]
// 2. rootNode [RADFormNode]
nonVisualsNode.formManager = formManager;
nonVisualsNode.nodeArray = nodeArray;
// >> RADFormNode
// From RADFormNode:
// 1. form [DesignForm]
// 2. nonVisualsNode [NonVisualsNode]
// 3. menu [String]
rootNode.form = designForm;
rootNode.nonVisualsNode = nonVisualsNode;
rootNode.menu = null;
if (formManager2.getRADForm ().getTopLevelComponent () instanceof RADVisualFormContainer) {
rootNode.menu = ((RADVisualFormContainer)formManager2.getRADForm ().getTopLevelComponent ()).getFormMenu ();
}
convertComponentBack (formManager2.getRADForm ().getTopLevelComponent (), rootNode);
// >> FormManager
// 1. designForm [DesignForm]
// 2. rootNode [RADFormNode]
formManager.designForm = designForm;
formManager.rootNode = rootNode;
designForm.formManager = formManager;
return designForm;
}
private static void convertComponentBack (RADComponent comp, RADNode contNode) {
if (contNode instanceof RADMenuNode) {
// >> RADMenuNode
// 1. nodeArray [RADNodeArray]
RADNodeArray nodeArray = new RADNodeArray ();
// >> RADNodeArray
// 1. containerNode [RADContainer]
// 2. array [Object[] ]
nodeArray.containerNode = (RADMenuNode)contNode;
RADComponent[] children = ((RADMenuComponent)comp).getSubBeans ();
RADNode[] childrenNodes = new RADNode [children.length];
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof RADMenuComponent) {
childrenNodes[i] = new RADMenuNode ();
} else if (children[i] instanceof RADMenuItemComponent) {
childrenNodes[i] = new RADMenuItemNode ();
} else {
childrenNodes[i] = new RADNode (); // [PENDING - can X2 menu contain RADNodes?]
}
convertComponentBack (children[i], childrenNodes[i]);
}
nodeArray.array = childrenNodes;
((RADMenuNode)contNode).nodeArray = nodeArray;
}
if (contNode instanceof RADContainerNode) {
// >> RADContainerNode
// 1. nodeArray [RADNodeArray]
// 2. designLayout [DesignLayout]
// 3. radLayoutNode [RADLayoutNode]
RADNodeArray nodeArray = new RADNodeArray ();
// >> RADNodeArray
// 1. containerNode [RADContainer]
// 2. array [Object[] ]
nodeArray.containerNode = (RADContainerNode)contNode;
RADComponent[] children = ((RADVisualContainer)comp).getSubComponents ();
RADNode[] childrenNodes = new RADNode [children.length];
for (int i = 0; i < children.length; i++) {
if (children[i] instanceof RADVisualContainer) {
childrenNodes[i] = new RADContainerNode ();
} else if (children[i] instanceof RADVisualComponent) {
childrenNodes[i] = new RADVisualNode ();
} else {
childrenNodes[i] = new RADNode ();
}
convertComponentBack (children[i], childrenNodes[i]);
}
nodeArray.array = childrenNodes;
DesignLayout designLayout = ((RADVisualContainer)comp).getDesignLayout ();
org.netbeans.modules.form.compat2.RADLayoutNode layoutNode = new org.netbeans.modules.form.compat2.RADLayoutNode ();
// >> RADLayoutNode
// 1. designLayout [DesignLayout]
// 2. layoutName [String] (can be "" ???) // NOI18N
layoutNode.designLayout = designLayout;
layoutNode.layoutName = ""; // [PENDING - check] // NOI18N
((RADContainerNode)contNode).nodeArray = nodeArray;
((RADContainerNode)contNode).designLayout = designLayout;
((RADContainerNode)contNode).radLayoutNode = layoutNode;
}
if (contNode instanceof RADVisualNode) {
// >> RADVisualNode
// 1. designLayout [DesignLayout]
// 2. layoutName [String] (can be "" ???) // NOI18N
((RADVisualNode)contNode).constraints = ((RADVisualComponent)comp).getConstraintsMap ();
}
Hashtable changedProperties = new Hashtable ();
Hashtable handlersTable = new Hashtable ();
HashMap propertiesMap = new HashMap ();
RADComponent.RADProperty[] newProperties = comp.getAllProperties ();
for (int i = 0; i < newProperties.length; i++) {
if (newProperties[i].isChanged ()) {
Object changedValue = null;
try {
changedValue = newProperties[i].getValue ();
} catch (Exception e) {
if (Boolean.getBoolean ("netbeans.debug.exceptions")) e.printStackTrace (); // NOI18N
// problem getting value => ignore this property
continue;
}
PropertyDescriptor desc = newProperties[i].getPropertyDescriptor ();
String propName = desc.getName ();
changedProperties.put (propName, propName);
propertiesMap.put (propName, changedValue);
}
}
// >> RADNode
// 1. beanClass [Class]
// 2. changedProperties [Hashtable]
// 3. handlersTable [Hashtable]
// 4. componentName [String]
// 5. hasHiddenState [boolean]
// 6. propertiesMap [Map]
contNode.beanClass = comp.getBeanClass ();
contNode.changedProperties = changedProperties;
contNode.handlersTable = comp.getEventsList ().getEventNames ();
contNode.componentName = comp.getName ();
contNode.hasHiddenState = false; // [PENDING]
contNode.propertiesMap = propertiesMap;
}
// -----------------------------------------------------------------------------
// X2 Object Streams
public static class X2ObjectOutputStream extends ObjectOutputStream {
public X2ObjectOutputStream (OutputStream os) throws IOException {
super (os);
}
/** Calls super annotateClass and then write the index of the classloader of this class.
* @see NbObjectInputStream
*/
protected void annotateClass(Class cl) throws IOException {
super.annotateClass(cl);
writeByte(LOADER_DEFAULT);
}
}
// -----------------------------------------------------------------------------
// Safe Serialization
public static void writeSafely (ObjectOutput oo, Object obj)
throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream (200);
ObjectOutputStream oos = new X2ObjectOutputStream (bos); // [PENDING!!!]
oos.writeObject (obj);
oos.flush ();
bos.close ();
oo.writeInt (bos.size ());
oo.write (bos.toByteArray ());
}
public static Object readSafely (ObjectInput oi)
throws IOException, ClassNotFoundException {
int size = oi.readInt ();
byte[] byteArray = new byte [size];
oi.readFully (byteArray, 0, size);
ByteArrayInputStream bis = new ByteArrayInputStream (byteArray);
ObjectInputStream ois = new org.openide.util.io.NbObjectInputStream (bis);
Object obj = ois.readObject ();
bis.close ();
return obj;
}
}
/*
* Log
* 30 Gandalf 1.29 4/14/00 Jesse Glick Modified to permit
* loading of forms with old package names. On behalf of Trung.
* 29 Gandalf 1.28 1/13/00 Ian Formanek NOI18N #2
* 28 Gandalf 1.27 1/5/00 Ian Formanek NOI18N
* 27 Gandalf 1.26 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 26 Gandalf 1.25 10/8/99 Petr Hamernik closing input stream
* fixed (canLoad method)
* 25 Gandalf 1.24 9/24/99 Ian Formanek New system of changed
* properties in RADComponent - Fixes bug 3584 - Form Editor should try to
* enforce more order in the XML elements in .form.
* 24 Gandalf 1.23 9/10/99 Ian Formanek Separators improved
* 23 Gandalf 1.22 9/8/99 Ian Formanek Fixed last change
* 22 Gandalf 1.21 9/7/99 Ian Formanek Improved error messages
* if form loading fails
* 21 Gandalf 1.20 7/25/99 Ian Formanek Variables management
* moved to RADComponent
* 20 Gandalf 1.19 7/14/99 Ian Formanek saving menu
* 19 Gandalf 1.18 7/14/99 Ian Formanek loaded menu is set on
* the form
* 18 Gandalf 1.17 7/14/99 Ian Formanek Loads Tuborg menus
* 17 Gandalf 1.16 7/11/99 Ian Formanek supportsAdvancedFeatures
* added
* 16 Gandalf 1.15 7/5/99 Ian Formanek getComponentInstance->getBeanInstance,
* getComponentClass->getBeanClass
* 15 Gandalf 1.14 6/9/99 Ian Formanek ---- Package Change To
* org.openide ----
* 14 Gandalf 1.13 5/31/99 Ian Formanek Fixed bug which caused
* the stored properties to be nulls
* 13 Gandalf 1.12 5/24/99 Ian Formanek Non-Visual components
* 12 Gandalf 1.11 5/24/99 Ian Formanek
* 11 Gandalf 1.10 5/16/99 Ian Formanek Fixed bug 1829 -
* Duplicate variable declaration .
* 10 Gandalf 1.9 5/16/99 Ian Formanek Persistence
* failure-proofness improved
* 9 Gandalf 1.8 5/16/99 Ian Formanek
* 8 Gandalf 1.7 5/15/99 Ian Formanek
* 7 Gandalf 1.6 5/15/99 Ian Formanek Fixed problem which
* prevented opening forms in Build 321
* 6 Gandalf 1.5 5/14/99 Ian Formanek
* 5 Gandalf 1.4 5/13/99 Ian Formanek
* 4 Gandalf 1.3 5/12/99 Ian Formanek
* 3 Gandalf 1.2 5/11/99 Ian Formanek Build 318 version
* 2 Gandalf 1.1 5/10/99 Ian Formanek
* 1 Gandalf 1.0 5/4/99 Ian Formanek
* $
*/